/**
 * Copyright (c) 2008, Keisuke Inoue, Syracuse Unviersity
 * All rights reserved.
 *
 */
package edu.syr.iis.web.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Transient;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.syr.iis.web.model.Message.WordListItem;

/**
 * @author kinoue
 *
 */
@Entity
public class DialogueAct
{
	// Classic bitwise arithmetics:  
	//   MATCH_FUNCTION + MATCH_DOMAIN = MATCH_DA
	//   MATCH_FUNCTION + MATCH_DOMAIN + MATCH_SEGMENT = MATCH_EXACT
	//
	public static final int MATCH_FUNCTION = 1;
	public static final int MATCH_DOMAIN = 2;
	public static final int MATCH_SEGMENT = 4;
	public static final int MATCH_DA = 3;
	public static final int MATCH_EXACT = 7; 
	
	private static Log log = LogFactory.getLog(DialogueAct.class);
	public static final int MAX_OPTION_LENGTH = 48;
	public static final int MAX_SNIPPET_LENGTH = 30;
	 
	int dialogueActId;

	Message message;
	User user;
	
	DialogueActLabel function;
	DialogueActLabel domain;
	
	Adjacency adjacency;
	DialogueAct adjacentDialogueAct;
	
	Date createdAt;
	Date lastSavedAt;
	
	int priority; 
	int startIndex;
	int endIndex;
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	public int getDialogueActId()
	{
		return dialogueActId;
	}
	
	public void setDialogueActId(int dialogueActId)
	{
		this.dialogueActId = dialogueActId;
	}
	
	@ManyToOne
	@JoinColumn(name = "messageId")
	public Message getMessage() {
		return message;
	}
	
	public void setMessage(Message message) {
		this.message = message;
	}

	@ManyToOne
	@JoinColumn(name = "userId")
	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	@ManyToOne
	@JoinColumn(name = "functionDALabelId")
	public DialogueActLabel getFunction()
	{
		return function;
	}
	
	public void setFunction(DialogueActLabel function)
	{
		this.function = function;
	}

	@ManyToOne
	@JoinColumn(name = "domainDALabelId")
	public DialogueActLabel getDomain()
	{
		return domain;
	}

	public void setDomain(DialogueActLabel domain)
	{
		this.domain = domain;
	}

	@ManyToOne
	@JoinColumn(name = "adjacencyId")
	public Adjacency getAdjacency() {
		return adjacency;
	}

	public void setAdjacency(Adjacency adjacency) {
		this.adjacency = adjacency;
	}
	
	@ManyToOne
	@JoinColumn(name = "adjacentDialogueActId")
	public DialogueAct getAdjacentDialogueAct() {
		return adjacentDialogueAct;
	}

	public void setAdjacentDialogueAct(DialogueAct adjacentDialogueAct) {
		this.adjacentDialogueAct = adjacentDialogueAct;
	}

	
	@Transient
	public String getLogString()
	{
		String logString = "  ID:          " + dialogueActId + "\n"; 
		if (function != null)
			logString += "  Function:    " + function.getLabel() + "\n";
		if (domain != null)
			logString += "  Domain:      " + domain.getLabel() + "\n";
		if (adjacency != null)
			logString += "  Adjacency:   " + adjacency.getLabel() + "\n";			
		if (adjacentDialogueAct != null)
			logString += "  Adjacent DA: " + adjacentDialogueAct.getTextSegment() + "\n";

		logString += "  StartIndex:  " + startIndex + "\n";
		logString += "  EndIndex:    " + endIndex + "\n";


		return logString;
	}

	@Transient
	public String getNextDialogueActDomainLabel()
	{
		DialogueAct nextDA = message.getNextDialogueAct(this);
		if (nextDA != null)
			if (nextDA.getDomain() == null)
				return "NA";
			else	
				return nextDA.getDomain().label;
		else
			return "END1";			
	}

	@Transient
	public String getNextDialogueActFunctionLabel()
	{
		DialogueAct nextDA = message.getNextDialogueAct(this);
		if (nextDA != null)
			if (nextDA.getFunction() == null)
				return "NA"; /* should not happen though! */
			else
				return nextDA.getFunction().label;
		else
			return "END1";			
	}

	@Transient
	public String getPreviousDialogueActDomainLabel()
	{
		DialogueAct nextDA = message.getPreviousDialogueAct(this);
		if (nextDA != null)
			if (nextDA.getDomain() == null)
				return "NA";
			else
				return nextDA.getDomain().label;
		else
			return "START1";			
	}

	@Transient
	public String getPreviousDialogueActFunctionLabel()
	{
		DialogueAct nextDA = message.getPreviousDialogueAct(this);
		if (nextDA != null)
			return nextDA.getFunction().label;
		else
			return "START1";			
	}
	
	@Transient
	public String getTextForSelectOption()
	{
		String text = "Message " + message.sequence + " (" + (function == null? "":function.getLabel()) + "): "; 
		String segment = getTextSegment();

		if (segment.length() < MAX_OPTION_LENGTH)
			text += " " + segment;
		else 
			text += " " + segment.substring(0, MAX_OPTION_LENGTH / 2) + "..." + segment.substring(segment.length() - (MAX_OPTION_LENGTH / 2 - 3)); 
		return text;
	}

	@Transient
	public String getExactlyMatchedDialogueActsString()
	{
		String matched = "";
		List<DialogueAct> dialogueActs = getExactlyMatchedDialogueActs();
			
		for (int i = 0; i < dialogueActs.size(); i++) 
		{
			matched += dialogueActs.get(i).getUser().getUserName() + "(<a href=\"#da" + dialogueActs.get(i).getDialogueActId() + "\">" + dialogueActs.get(i).getDialogueActId() + "</a>)";
			if (i < dialogueActs.size() - 1)
				matched += ", ";
		}			
		
		return matched;
	}
	
	
	@Transient
	public String getMatchedDialogueActsString()
	{
		String matched = "";
		List<DialogueAct> dialogueActs = getMatchedDialogueActs();
			
		for (int i = 0; i < dialogueActs.size(); i++) 
		{
			matched += dialogueActs.get(i).getUser().getUserName() + "(<a href=\"#da" + dialogueActs.get(i).getDialogueActId() + "\">" + dialogueActs.get(i).getDialogueActId() + "</a>)";
			if (i < dialogueActs.size() - 1)
				matched += ", ";
		}			
		
		return matched;
	}

	@Transient
	public int getNumFunctionMatched()
	{
		return getMatchedDialogueActs(MATCH_FUNCTION).size();
	}

	@Transient
	public int getNumMatched()
	{
		return getMatchedDialogueActs(MATCH_DA).size();
	}

	@Transient
	
	public int getNumExactlyMatched()	{
		return getMatchedDialogueActs(MATCH_EXACT).size();
	}
	
	
	
	@Transient
	public List<DialogueAct> getMatchedDialogueActs()
	{
		return getMatchedDialogueActs(MATCH_DA);
	}

	@Transient
	public List<DialogueAct> getExactlyMatchedDialogueActs()
	{
		return getMatchedDialogueActs(MATCH_EXACT);
	}
	
	//
	//
	@Transient
	public List<DialogueAct> getMatchedDialogueActs(int mode)
	{
		List<DialogueAct> matched = new ArrayList<DialogueAct>();		
		Set<DialogueAct> dialogueActs = message.getDialogueActs();
		
		for (DialogueAct dialogueAct: dialogueActs) {
			if (dialogueAct.getUser().userId != user.userId
					&& ((mode & MATCH_FUNCTION) == 0 
						|| (dialogueAct.getFunction() == null && function == null) 
						|| (dialogueAct.getFunction() != null && function != null
								&& dialogueAct.getFunction().getDialogueActLabelId() == function.getDialogueActLabelId()))
					&& ((mode & MATCH_DOMAIN) == 0
						|| (dialogueAct.getDomain() == null && domain == null) 
						|| (dialogueAct.getDomain() != null && domain != null 
								&& dialogueAct.getDomain().getDialogueActLabelId() == domain.getDialogueActLabelId()))
					&& ((mode & MATCH_SEGMENT) == 0
						|| (dialogueAct.getStartIndex() == startIndex && dialogueAct.getEndIndex() == endIndex))) 
					matched.add(dialogueAct);
		}
		return matched;
	}

	
	
	// XOR version. I thought it would be more useful, for removing redanduncies when
	// displaying: "exactly matched" and "matched", etc. but it makes impossible to
	// get statistics, so going back to old version.
	// 
	@Transient
	public List<DialogueAct> getMatchedDialogueActs0(int mode)
	{
		List<DialogueAct> matched = new ArrayList<DialogueAct>();		
		Set<DialogueAct> dialogueActs = message.getDialogueActs();
		
		// Using the XOR (^) operator, so that MATCH_DA means 
		// the text segments must not be matched.
		//
		for (DialogueAct dialogueAct: dialogueActs) {
			if (dialogueAct.getDialogueActId() != dialogueActId 
					&& dialogueAct.getUser().userId != user.userId
					&& (((mode & MATCH_FUNCTION) == 0) 
							^ (dialogueAct.getFunction() != null && function != null
									&& dialogueAct.getFunction().getDialogueActLabelId() == function.getDialogueActLabelId()))
					&& (((mode & MATCH_DOMAIN) == 0)
							^ (dialogueAct.getDomain() != null && domain != null
									&& dialogueAct.getDomain().getDialogueActLabelId() == domain.getDialogueActLabelId()))
					&& (((mode & MATCH_SEGMENT) == 0)
							^ (dialogueAct.getStartIndex() == startIndex && dialogueAct.getEndIndex() == endIndex))) 
					matched.add(dialogueAct);
		}
		return matched;
	}
	
	@Transient
	public String getTextSegmentSnippet() 
	{
		String text = "";
		String segment = getTextSegment();

		if (segment.length() < MAX_SNIPPET_LENGTH)
			text += " " + segment;
		else 
			text += " " + segment.substring(0, MAX_SNIPPET_LENGTH / 2) + "..." + segment.substring(segment.length() - (MAX_SNIPPET_LENGTH / 2 - 3)); 
		return text;
	}    
	
	
	@Transient
	public String getTextSegment() 
	{

		List<WordListItem> wordList = message.getWordList();
		String segment = new String("");

		for (WordListItem wordListItem: wordList)
			if (startIndex <= wordListItem.getIndex() && wordListItem.getIndex() <= endIndex)  
				segment += wordListItem.getWord() + " ";	

		return segment;
	}    

	@Basic
	public int getStartIndex() 
	{
		return startIndex;
	}
	public void setStartIndex(int startIndex) 
	{
		this.startIndex = startIndex;
	}
	public int getEndIndex() 
	{
		return endIndex;
	}
	public void setEndIndex(int endIndex) 
	{
		this.endIndex = endIndex;
	}
	public int getPriority() 
	{
		return priority;
	}
	public void setPriority(int priority) 
	{
		this.priority = priority;
	}

	public Date getCreatedAt() {
		return createdAt;
	}

	public void setCreatedAt(Date createdAt) {
		this.createdAt = createdAt;
	}

	public Date getLastSavedAt() {
		return lastSavedAt;
	}

	public void setLastSavedAt(Date lastSavedAt) {
		this.lastSavedAt = lastSavedAt;
	}
	
	
}
